#include "gameEngine.h"

GameEngine::GameEngine()
{
    frameCount=0;
    mesActions= new std::vector<AbstractSlot *>;
}


void GameEngine::GameLoop()
{
    int continuer=1;

    while(continuer)
    {
        currentTime=SDL_GetTicks();

        if(currentTime-lastTime>15)
        {
            lastTime=currentTime;
            keyboardState=SDL_GetKeyState(NULL);

             //    SDL_WaitEvent(&event);	//	Méthode qui attends qu'un événement se produise, blocante
            while(SDL_PollEvent(&event))        //	Méthode qui se déclenche lors qu'un événement se produit, non blocante
            {
                if(event.type==SDL_QUIT)
                {
                    continuer=0;
                }
                InputEventManagement();
            }
            EventManagement();
            for(int i=0;i<elements.size();i++)
            {
                if(elements[i]->state==0)
                {
                    elements.erase(elements.begin()+i);
                }
                else
                {
                    elements.at(i)->Update();
                }
            }

            CheckCollision();
            DoAction();
            SetGravity();
            CalculPosition();
            DisplayFrame();
            SDL_GL_SwapBuffers();
            frameCount++;
        }
        else /* Si ça fait moins de 30ms depuis le dernier tour de boucle, on endort le programme le temps qu'il faut */
        {
            SDL_Delay(15 - (currentTime - lastTime));
        }
    }
}

void GameEngine::InitSDL(int width, int height)
{
    windowWidth=width;windowHeight=height;
    mousePressed=0;mouseFirstPressed=0;
    firstMotionMouse=0;

    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO );					//	Méthode de la librairie SDL pour initialiser ses différents composants
    SDL_SetVideoMode(windowWidth, windowHeight, 32, SDL_HWSURFACE | SDL_GL_DOUBLEBUFFER | SDL_OPENGL);	//	Définit la taille de la fenêtre
    SDL_WM_SetCaption("Sdl",NULL);	//	Méthode utilisé pour définir le titre de la fenêtre
}

void GameEngine::InputEventManagement()
{
    for(int i=0;i<elements.size();i++)
    {
        elements.at(i)->CheckInputDelegates();
    }
}

void GameEngine::DoAction()
{
    for(int i=0;i<mesActions->size();i++)
    {
        mesActions->at(i)->Run();
    }
}

void GameEngine::EventManagement()
{

    for(int i=0;i<delegates.size();i++)
    {
        delegates.at(i)->Update();
    }
    for(int i=0;i<elements.size();i++)
    {
        elements.at(i)->CheckDelegates();
    }
}

void GameEngine::InitGL()
{
    mat_specular = new float[3];
    mat_specular[0]=1.0; mat_specular[1]=1.0;mat_specular[2]=1.0;

    mat_shininess = new float[1];
    mat_shininess[0]=50.0;

    light_position =  new float[4];
    light_position[0]=1.0; light_position[1]=1.0; light_position[2]=1.0, light_position[3]=0.0;

    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
   glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glClearColor(0.0, 0.2, 0.7, 0);
    glEnable(GL_DEPTH_TEST);
    glEnable (GL_BLEND);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

void GameEngine::DisplayFrame()
{
    glMatrixMode(GL_MODELVIEW);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    pow.SetPOW();

    for(int i=0;i<elements.size();i++)
    {
        elements.at(i)->Display();
    }
}

void GameEngine::ColorPicking()
{
    glMatrixMode(GL_MODELVIEW);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    pow.SetPOW();

    for(int i=0;i<elements.size();i++)
    {
        elements.at(i)->Display();
    }
}

void GameEngine::InitOrthoProjection(float aLowerBoundx, float aUpperBoundx, float aLowerBoundy, float aUpperBoundy)
{
    dimension=2;
    lowerBoundGLx=aLowerBoundx;upperBoundGLx=aUpperBoundx;lowerBoundGLy=aLowerBoundy;upperBoundGLy=aUpperBoundy;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(lowerBoundGLx, upperBoundGLx, lowerBoundGLy, upperBoundGLy, -1, 1000);
}

void GameEngine::InitFrustsumProjection()
{
    dimension=3;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90.0f, 1.0f, 1.0f, 500.0f);
}


void GameEngine::SetGravity()
{
    for(int i=0;i<elements.size();i++)
    {
        if(elements[i]->movable==1)
        {
            if(elements[i]->gravity)
            {
                elements[i]->velocity->AddAcceleration(new Vectorf(0.0,elements[i]->valGravity,0.0));
            }
        }
    }
}

void GameEngine::CheckCollision()
{
    for(int i=0; i<collisions.size();i++)
    {
        collisions.at(i)->CheckCollision();
    }
}

void GameEngine::CalculPosition()
{
    for(int i=0;i<elements.size();i++)
    {
        if(elements[i]->movable==1)
        {
            elements[i]->velocity->Do();
        }
    }
}

void GameEngine::AddElement(Displayable * aObject)
{
    printf("LOL \n");
        aObject->event=&event;
        printf(" 2 EME LOL \n");
        aObject->SetPicking(0,0,elements.size()+1);
        printf("3 EME LOL \n");
	elements.push_back(aObject);
}


int GameEngine::MoveCamera()
{
    int x=event.motion.x;
    int y=event.motion.y;

    pow.phi  +=(x-anchorX )*0.05;
    pow.teta +=(y-anchorY)*0.05;

    pow.SetVecteurDirecteur();

    anchorX=250;
    anchorY=250;

  //  SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
    SDL_WarpMouse(250, 250);
  //  SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
}

int GameEngine::sLMBD()
{
    if(event.type==SDL_MOUSEBUTTONDOWN)
    {
        if(event.button.button== SDL_BUTTON_LEFT)
        {
            return 1;
        }
    }
    return 0;
}

int GameEngine::sMM()
{
    if(event.type==SDL_MOUSEMOTION)
    {
        if(firstMotionMouse==0)
        {
            anchorX=250;
            anchorY=250;
            firstMotionMouse=1;
        }
        return 1;
    }
    return 0;
}

void GameEngine::DisplayPicking()
{
    glMatrixMode(GL_MODELVIEW);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    pow.SetPOW();

    for(int i=0;i<elements.size();i++)
    {
        if(elements[i]->picking==1)
        {
            elements[i]->Picking();
        }
    }
}

void GameEngine::DefineCamera()
{
    AbstractDelegate * delegate = new Delegate<GameEngine>(&GameEngine::sMM,this);
    delegate->Connect(new Slot<GameEngine>(&GameEngine::MoveCamera,this));
    delegates.push_back(delegate);
}
